/*  Copyright (C) 2008  Alexander Blyzniuchenko (BlezAlex)

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;

namespace MediaDC.Native
{
    static class NativeConsole
    {
        private static bool hasConsole = false;
        private static IntPtr conOut;
        private static IntPtr oldOut;

        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern bool AllocConsole();

        [DllImport("kernel32.dll", SetLastError = false)]
        private static extern bool FreeConsole();

        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern IntPtr GetStdHandle(int nStdHandle);

        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern bool SetStdHandle(int nStdHandle, IntPtr hConsoleOutput);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr CreateFile(
            string fileName,
            int desiredAccess,
            int shareMode,
            IntPtr securityAttributes,
            int creationDisposition,
            int flagsAndAttributes,
            IntPtr templateFile);

        [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
        private static extern bool CloseHandle(IntPtr handle);

        public static void CreateConsole()
        {
            if (hasConsole)
                return;

            if (oldOut == IntPtr.Zero)
                oldOut = GetStdHandle(-11);

            if (!AllocConsole())
                throw new Exception("AllocConsole() failed");

            conOut = CreateFile("CONOUT$", 0x40000000, 2, IntPtr.Zero, 3, 0, IntPtr.Zero);

            if (!SetStdHandle(-11, conOut))
                throw new Exception("SetStdHandle() failed");

            StreamToConsole();

            hasConsole = true;
        }

        private static void StreamToConsole()
        {
            Stream cstm = Console.OpenStandardOutput();
            StreamWriter cstw = new StreamWriter(cstm, Encoding.GetEncoding(866));
            cstw.AutoFlush = true;
            Console.SetOut(cstw);
            Console.SetError(cstw);
        }

        public static void ReleaseConsole()
        {
            if (!hasConsole)
                return;

            if (!CloseHandle(conOut))
                throw new Exception("CloseHandle() failed");

            conOut = IntPtr.Zero;

            if (!FreeConsole())
                throw new Exception("FreeConsole() failed");

            if (!SetStdHandle(-11, oldOut))
                throw new Exception("SetStdHandle() failed");

            StreamToConsole();

            hasConsole = false;
        }
    }
}